一、函数原型
#include <unistd.h> int ioctl(int fd, int request, .../* void *arg */); 返回:成功返回0,否则为-1
二、和网络相关的请求(request)
(1)套接字操作
(2)文件操作
(3)接口操作
(4)ARP告诉缓存操作
(5)路由表操作
(6)流系统
三、request参数及arg地址必须指向的数据类型
四、案列:获取所有网络设备接口名称
#include <stdio.h> #include <stdlib.h> #include <errno.h> #include <sys/ioctl.h> #include <sys/socket.h> #include <net/if.h> struct ifreq *get_ifreq(); int main(int argc, char **argv) { struct ifreq *ifr, *tobefree; ifr = tobefree = get_ifreq(); do { printf("%s\n", ifr->ifr_name); ifr++; } while (ifr->ifr_name[0] != 0); free(tobefree); exit(0); } struct ifreq *get_ifreq() { int sockfd, len, lastlen; char *buf; struct ifconf ifc; sockfd = socket(AF_INET, SOCK_DGRAM, 0); lastlen = 0; len = 40 * sizeof(struct ifreq); /* initial buffer size guess */ for ( ; ; ) { buf = malloc(len); ifc.ifc_len = len; ifc.ifc_buf = buf; if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) { if (errno != EINVAL || lastlen != 0) { perror("ioctl"); exit(-1); } } else { if (ifc.ifc_len == lastlen) { break; /* success, len has not changed */ } lastlen = ifc.ifc_len; } len += 10 * sizeof(struct ifreq); /* increment */ free(buf); } return ((struct ifreq *)ifc.ifc_buf); }
五、关于ioctl函数应该注意
六、get_ifi_info函数
#include "unpifi.h" struct ifi_info *get_ifi_info(int family, int doaliases) { int sockfd, len, lastlen, flags, myflags, idx = 0, hlen = 0; char *ptr, *buf, lastname[IFNAMSIZ], *cptr, *haddr, *sdlname; struct ifconf ifc; struct ifreq *ifr, ifrcopy; struct sockaddr_in *sinptr; struct sockaddr_in6 *sin6ptr; struct ifi_info *ifi, *ifihead, **ifipnext; sockfd = socket(family, SOCK_DGRAM, 0); lastlen = 0; len = 100 * sizeof(struct ifreq); /* initial buffer size guess */ for ( ; ; ) { buf = malloc(len); ifc.ifc_len = len; ifc.ifc_buf = buf; if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) { if (errno != EINVAL || lastlen != 0) { perror("ioctl"); exit(-1); } } else { if (ifc.ifc_len == lastlen) { break; /* success, len has not changed */ } lastlen = ifc.ifc_len; } len += 10 * sizeof(struct ifreq); /* increment */ free(buf); } ifihead = NULL; ifipnext = &ifihead; lastname[0] = 0; sdlname = NULL; for (ptr = buf; ptr < buf + ifc.ifc_len; ) { ifr = (struct ifreq *) ptr; #ifdef HAVE_SOCKADDR_SA_LEN len = max(sizeof(struct sockaddr), ifr->ifr_addr.sa_len); #else switch (ifr->ifr_addr.sa_family) { #ifdef IPV6 case AF_INET6: len = sizeof(struct sockaddr_in6); break; #endif case AF_INET: default: len = sizeof(struct sockaddr); break; } #endif /* HAVE_SOCKADDR_SA_LEN */ ptr += sizeof(ifr->ifr_name) + len + 8; /* for next one in buffer */ #ifdef HAVE_SOCKADDR_DL_STRUCT /* assumes that AF_LINK precedes AF_INET or AF_INET6 */ if (ifr->ifr_addr.sa_family == AF_LINK) { struct sockaddr_dl *sdl = (struct sockaddr_dl *)&ifr->ifr_addr; sdlname = ifr->ifr_name; idx = sdl->sdl_index; haddr = sdl->sdl_data + sdl->sdl_nlen; hlen = sdl->sdl_alen; } #endif if (ifr->ifr_addr.sa_family != family) { continue; /* ignore if not desired address family */ } myflags = 0; if ( (cptr = strchr(ifr->ifr_name, ':')) != NULL) { *cptr = 0; /* replace colon with null */ } if (strncmp(lastname, ifr->ifr_name, IFNAMSIZ) == 0) { if (doaliases == 0) continue; /* already processed this interface */ myflags = IFI_ALIAS; } memcpy(lastname, ifr->ifr_name, IFNAMSIZ); ifrcopy = *ifr; ioctl(sockfd, SIOCGIFFLAGS, &ifrcopy); flags = ifrcopy.ifr_flags; if ((flags & IFF_UP) == 0) { continue; /* ignore if interface not up */ } ifi = calloc(1, sizeof(struct ifi_info)); *ifipnext = ifi; /* prev points to this new one */ ifipnext = &ifi->ifi_next; /* pointer to next one goes here */ ifi->ifi_flags = flags; /* IFF_xxx values */ ifi->ifi_myflags = myflags; /* IFI_xxx values */ #if defined(SIOCGIFMTU) && defined(HAVE_STRUCT_IFREQ_IFR_MTU) ioctl(sockfd, SIOCGIFMTU, &ifrcopy); ifi->ifi_mtu = ifrcopy.ifr_mtu; #else ifi->ifi_mtu = 0; #endif memcpy(ifi->ifi_name, ifr->ifr_name, IFI_NAME); ifi->ifi_name[IFI_NAME-1] = '\0'; /* If the sockaddr_dl is from a different interface, ignore it */ if (sdlname == NULL || strcmp(sdlname, ifr->ifr_name) != 0) { idx = hlen = 0; } ifi->ifi_index = idx; ifi->ifi_hlen = hlen; if (ifi->ifi_hlen > IFI_HADDR) { ifi->ifi_hlen = IFI_HADDR; } if (hlen) { memcpy(ifi->ifi_haddr, haddr, ifi->ifi_hlen); } switch (ifr->ifr_addr.sa_family) { case AF_INET: sinptr = (struct sockaddr_in *) &ifr->ifr_addr; ifi->ifi_addr = calloc(1, sizeof(struct sockaddr_in)); memcpy(ifi->ifi_addr, sinptr, sizeof(struct sockaddr_in)); #ifdef SIOCGIFBRDADDR if (flags & IFF_BROADCAST) { ioctl(sockfd, SIOCGIFBRDADDR, &ifrcopy); sinptr = (struct sockaddr_in *) &ifrcopy.ifr_broadaddr; ifi->ifi_brdaddr = calloc(1, sizeof(struct sockaddr_in)); memcpy(ifi->ifi_brdaddr, sinptr, sizeof(struct sockaddr_in)); } #endif #ifdef SIOCGIFDSTADDR if (flags & IFF_POINTOPOINT) { ioctl(sockfd, SIOCGIFDSTADDR, &ifrcopy); sinptr = (struct sockaddr_in *) &ifrcopy.ifr_dstaddr; ifi->ifi_dstaddr = calloc(1, sizeof(struct sockaddr_in)); memcpy(ifi->ifi_dstaddr, sinptr, sizeof(struct sockaddr_in)); } #endif break; case AF_INET6: sin6ptr = (struct sockaddr_in6 *) &ifr->ifr_addr; ifi->ifi_addr = calloc(1, sizeof(struct sockaddr_in6)); memcpy(ifi->ifi_addr, sin6ptr, sizeof(struct sockaddr_in6)); #ifdef SIOCGIFDSTADDR if (flags & IFF_POINTOPOINT) { ioctl(sockfd, SIOCGIFDSTADDR, &ifrcopy); sin6ptr = (struct sockaddr_in6 *) &ifrcopy.ifr_dstaddr; ifi->ifi_dstaddr = calloc(1, sizeof(struct sockaddr_in6)); memcpy(ifi->ifi_dstaddr, sin6ptr, sizeof(struct sockaddr_in6)); } #endif break; default: break; } } free(buf); return (ifihead); /* pointer to first structure in linked list */ } void free_ifi_info(struct ifi_info *ifihead) { struct ifi_info *ifi, *ifinext; for (ifi = ifihead; ifi != NULL; ifi = ifinext) { if (ifi->ifi_addr != NULL) { free(ifi->ifi_addr); } if (ifi->ifi_brdaddr != NULL) { free(ifi->ifi_brdaddr); } if (ifi->ifi_dstaddr != NULL) { free(ifi->ifi_dstaddr); } ifinext = ifi->ifi_next; /* can't fetch ifi_next after free() */ free(ifi); /* the ifi_info{} itself */ } } struct ifi_info *Get_ifi_info(int family, int doaliases) { struct ifi_info *ifi; if ( (ifi = get_ifi_info(family, doaliases)) == NULL) { printf("get_ifi_info error\n"); exit(-1); } return(ifi); }
七、unpifi.h头文件
#ifndef __unp_ifi_h #define __unp_ifi_h #include <stdio.h> #include <errno.h> #include <stdlib.h> #include <string.h> #include <net/if.h> #include <netinet/in.h> #include <sys/ioctl.h> #define IFI_NAME 16 /* same as IFNAMSIZ in <net/if.h> */ #define IFI_HADDR 8 /* allow for 64-bit EUI-64 in future */ struct ifi_info { char ifi_name[IFI_NAME]; /* interface name, null-terminated */ short ifi_index; /* interface index */ short ifi_mtu; /* interface MTU */ u_char ifi_haddr[IFI_HADDR]; /* hardware address */ u_short ifi_hlen; /* # bytes in hardware address: 0, 6, 8 */ short ifi_flags; /* IFF_xxx constants from <net/if.h> */ short ifi_myflags; /* our own IFI_xxx flags */ struct sockaddr *ifi_addr; /* primary address */ struct sockaddr *ifi_brdaddr; /* broadcast address */ struct sockaddr *ifi_dstaddr; /* destination address */ struct ifi_info *ifi_next; /* next of these structures */ }; #define IFI_ALIAS 1 /* ifi_addr is an alias */ /* function prototypes */ char *sock_ntop_host(const struct sockaddr *, socklen_t); void free_ifi_info(struct ifi_info *); struct ifi_info *get_ifi_info(int, int); struct ifi_info *Get_ifi_info(int, int); #endif /* __unp_ifi_h */
八、sock_ntop_host函数
#include <stdio.h> #include <string.h> #include <arpa/inet.h> #include <sys/un.h> #ifdef HAVE_SOCKADDR_DL_STRUCT #include <net/if_dl.h> #endif char *sock_ntop_host(const struct sockaddr *sa, socklen_t salen) { static char str[128]; /* Unix domain is largest */ switch (sa->sa_family) { case AF_INET: { struct sockaddr_in *sin = (struct sockaddr_in *) sa; if (inet_ntop(AF_INET, &sin->sin_addr, str, sizeof(str)) == NULL) return(NULL); return(str); } #ifdef IPV6 case AF_INET6: { struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) sa; if (inet_ntop(AF_INET6, &sin6->sin6_addr, str, sizeof(str)) == NULL) return(NULL); return(str); } #endif #ifdef AF_UNIX case AF_UNIX: { struct sockaddr_un *unp = (struct sockaddr_un *) sa; /* OK to have no pathname bound to the socket: happens on every connect() unless client calls bind() first. */ if (unp->sun_path[0] == 0) strcpy(str, "(no pathname bound)"); else snprintf(str, sizeof(str), "%s", unp->sun_path); return(str); } #endif #ifdef HAVE_SOCKADDR_DL_STRUCT case AF_LINK: { struct sockaddr_dl *sdl = (struct sockaddr_dl *) sa; if (sdl->sdl_nlen > 0) snprintf(str, sizeof(str), "%*s", sdl->sdl_nlen, &sdl->sdl_data[0]); else snprintf(str, sizeof(str), "AF_LINK, index=%d", sdl->sdl_index); return(str); } #endif default: snprintf(str, sizeof(str), "sock_ntop_host: unknown AF_xxx: %d, len %d", sa->sa_family, salen); return(str); } return (NULL); }